package one.stand.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.vioao.wechat.api.component.ComponentApi;
import com.github.vioao.wechat.bean.response.BaseResponse;
import com.github.vioao.wechat.bean.response.component.CreatePreAuthCodeResponse;
import com.github.vioao.wechat.bean.response.component.GetAuthorizerInfoResponse;
import com.github.vioao.wechat.bean.response.component.QueryAuthResponse;
import com.jmp.base.dto.*;
import com.jmp.feign.AccountFeign;
import com.jmp.feign.WechatFeign;
import lombok.extern.slf4j.Slf4j;
import one.stand.code.RedisCode;
import one.stand.config.ComponentConfig;
import one.stand.enums.LoginEnum;
import one.stand.mapper.VersionMapper;
import one.stand.model.ResultModel;
import one.stand.model.VersionModel;
import one.stand.request.CompanyAccountRequest;
import one.stand.service.CodeService;
import one.stand.service.ComponentService;
import one.stand.service.DomainService;
import one.stand.util.AssertUtil;
import one.stand.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Objects;

/**
 * @author: QIK
 * @CreateDate: 2019/5/9 10:22
 */
@Service
@Slf4j
public class ComponentServiceImpl implements ComponentService {
    private ComponentApi componentApi = new ComponentApi();

    @Autowired
    private AccountFeign accountFeign;
    @Autowired
    private WechatFeign wechatFeign;

    @Lazy
    @Autowired
    private DomainService domainService;
    @Autowired
    private ComponentConfig componentConfig;
    @Lazy
    @Autowired
    private CodeService codeService;
    @Autowired
    protected RedisUtil redisUtil;
    /**
     * 小程序代码版本管理
     */
    @Autowired
    protected VersionMapper versionMapper;

    @Override
    public String createPreAuthCode() {
        String code = null;
        ResultModel<WechatComponentTokenResponse> componentTokenResponseResultModel = wechatFeign.componentToken();
        AssertUtil.isTrue(componentTokenResponseResultModel);
        String token = componentTokenResponseResultModel.getData().getToken();
        CreatePreAuthCodeResponse createPreAuthCodeResponse = componentApi.createPreAuthCode(token, componentConfig.getAppid());
        if (createPreAuthCodeResponse.isSuccess()) {
            code = createPreAuthCodeResponse.getPreAuthCode();
        }
        return code;
    }

    @Override
    public ResultModel<String> componentloginpage(CompanyAccountRequest request) {
        if (StringUtils.isEmpty(request.getAppId()) || null == request.getAccountType() || StringUtils.isEmpty(request.getAppSecret()) || StringUtils.isEmpty(request.getAppName())) {
            return ResultModel.checkParamFail();
        }

        AccountSaveRequest accountSaveRequest = AccountSaveRequest.builder()
                .companyId(request.getCId().intValue())
                .accountType(request.getAccountType())
                .appid(request.getAppId())
                .appSecret(request.getAppSecret())
                .appName(request.getAppName())
                .build();
        ResultModel resultModel = accountFeign.save(accountSaveRequest);
        AssertUtil.isTrue(resultModel);

        String loginPage = componentApi.getComponentLoginPage(componentConfig.getAppid(), createPreAuthCode(), componentConfig.getRedirectUri(), "3", request.getAppId());
        return ResultModel.success(loginPage + "&type=" + request.getAccountType());
    }

    @Override
    public QueryAuthResponse queryAuth(String code) {
        ResultModel<WechatComponentTokenResponse> componentTokenResponseResultModel = wechatFeign.componentToken();
        AssertUtil.isTrue(componentTokenResponseResultModel);
        String token = componentTokenResponseResultModel.getData().getToken();
        QueryAuthResponse respons = componentApi.queryAuth(token, componentConfig.getAppid(), code);
        return respons;
    }

    @Override
    public ResultModel getAuthorizerInfo(CompanyAccountRequest request) {
        if (StringUtils.isEmpty(request.getAppId())) {
            return ResultModel.checkParamFail();
        }
        String key = RedisCode.getAuthorizerRefreshTokenKey(request.getAppId());
        ResultModel<WechatComponentTokenResponse> componentTokenResponseResultModel = wechatFeign.componentToken();
        AssertUtil.isTrue(componentTokenResponseResultModel);
        String token = componentTokenResponseResultModel.getData().getToken();
        GetAuthorizerInfoResponse response = componentApi.getAuthorizerInfo(token, componentConfig.getAppid(), request.getAppId());
        QueryAuthResponse info = response.getAuthorizationInfo();
        if (response.isSuccess()) {
            token = response.getAuthorizationInfo().getAuthorizerAccessToken();
            if (StringUtils.isEmpty(token)) {
                token = response.getAuthorizationInfo().getAuthorizerRefreshToken();
            }
            redisUtil.set(key, token);
        }
        info.setAppid(null);
        info.setAuthorizerAccessToken(null);
        info.setAuthorizerRefreshToken(null);
        response.setAuthorizationInfo(info);
        return ResultModel.success(response);
    }

    @Override
    public ResultModel componentCallBack(CompanyAccountRequest request) {
        if (StringUtils.isEmpty(request.getAuthCode()) || StringUtils.isEmpty(request.getAppId())) {
            return ResultModel.checkParamFail();
        }
        QueryAuthResponse response = queryAuth(request.getAuthCode());
        log.info("授权成功后返回数据：{}", JSON.toJSONString(response));
        if (!response.getErrcode().equals(0)) {
            return ResultModel.fail();
        }
        ResultModel<WechatAuthorizerTokenResponse> authorizerTokenResponseResultModel = wechatFeign.authorizerToken(WechatAuthorizerTokenRequest.builder().appId(request.getAppId()).build());
        AssertUtil.isTrue(authorizerTokenResponseResultModel);
        String token = authorizerTokenResponseResultModel.getData().getToken();
        log.info("获取代理小程序Token:{}", token);

        AccountAuthRequest accountAuthRequest = AccountAuthRequest.builder()
                .appId(request.getAppId())
                .build();
        ResultModel<AccountResponse> resultModel = accountFeign.auth(accountAuthRequest);
        AssertUtil.isTrue(resultModel);
        AccountResponse model = resultModel.getData();

        BaseResponse baseResponse = domainService.setWebViewDomain(request.getAppId(), null);
        log.info("授权后设置白名单：{}", baseResponse.toString());
        LoginEnum loginEnum = LoginEnum.getByAccountType(model.getAccountType());
        WechatTemplateInitRequest wechatTemplateInitRequest = WechatTemplateInitRequest.builder()
                .companyId(model.getCompanyId())
                .loginEnum(loginEnum)
                .appId(model.getAppId())
                .build();
        wechatFeign.templateInit(wechatTemplateInitRequest);

        //验证是否绑定完两个小程序
        AccountCompanyIdRequest accountCompanyIdRequest = AccountCompanyIdRequest.builder()
                .companyId(model.getCompanyId())
                .loginEnum(LoginEnum.USER)
                .build();
        ResultModel<AccountResponse> accountResponseResultModel = accountFeign.getCompanyId(accountCompanyIdRequest);
        AccountResponse companyAccountModel = accountResponseResultModel.isSuccess() ? accountResponseResultModel.getData() : null;
        if (Objects.isNull(companyAccountModel)) {
            log.warn("小程序账号不齐全不进行发布操作");
        } else {
            commit(companyAccountModel.getAppId(), companyAccountModel.getAccountType());
            log.info("进行发布小程序");
        }
        return ResultModel.success();
    }

    @Async("asyncServiceExecutor")
    public void commit(String appId, Integer type) {
        VersionModel versionModel = versionMapper.select(new VersionModel() {{
            setVersionState(1);
            setVersionType(type);
        }});
        if (null != versionModel) {
            log.info("开始代码提交");
            codeService.commit(appId, versionModel.getVersionId(), true);
        }
    }
}

